package com.simulation.utils;

import com.alibaba.fastjson.JSONObject;
import com.jcraft.jsch.*;
import com.simulation.component.AsyncEventHandler;
import com.simulation.entity.MessageEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.InputStream;

/**
 * @author zhangxn
 * @date 2022/12/4  11:23
 */
@Component
@Slf4j
public class LinuxShellComponent {

    @Autowired
    private AsyncEventHandler asyncEventHandler;

    private Session session;
    // 其他方法实现放别的章节分开展示

    @Value("${qemu.ip}")
    private String ip;

    @Value("${qemu.username}")
    private String username;

    @Value("${qemu.password}")
    private String password;
    /**
     * 远程登录
     *
     * @return
     * @throws JSchException
     */
    public void login() {
        try {
            JSch jsch = new JSch();
            session = jsch.getSession(username, ip, 61191);
            session.setPassword(password);
            // 设置第一次登陆的时候提示，可选值:(ask | yes | no)
            session.setConfig("StrictHostKeyChecking", "no");
            // 连接超时
            session.connect(1000 * 10);

        } catch (JSchException e) {
            System.out.println("登录时发生错误！");
            e.printStackTrace();
        }
    }

    /**
     * 关闭连接
     */
    public void close() {
        if (session.isConnected())
            session.disconnect();
    }

    /**
     * 执行命令
     *
     * @param command
     * @return
     * @throws Exception
     */
    public String executeShell(String command, String type) throws Exception {

        byte[] tmp = new byte[1024];
        StringBuffer resultBuffer = new StringBuffer(); // 命令返回的结果

        Channel channel = session.openChannel("exec");
        ChannelExec exec = (ChannelExec) channel;
        // 返回结果流（命令执行错误的信息通过getErrStream获取）
        InputStream stdStream = exec.getInputStream();
        exec.setCommand(command);
        exec.connect();
        try {
            // 开始获得SSH命令的结果
            while (true) {
                while (stdStream.available() > 0) {
                    int i = stdStream.read(tmp, 0, 1024);
                    if (i < 0) break;
                    resultBuffer.append(new String(tmp, 0, i));
                    MessageEvent messageEvent = new MessageEvent();
                    JSONObject jsonObject =  new JSONObject();
                    jsonObject.put("type", type);
                    jsonObject.put("message", new String(tmp, 0, i));
                    messageEvent.setMessage(jsonObject.toJSONString());
                    messageEvent.setClientId("123456");
                    asyncEventHandler.asyncEventPost(messageEvent);
                }
                if (exec.isClosed()) {
					log.info("shell执行返回数据",resultBuffer.toString());
                    break;
                }
                try {
                    Thread.sleep(200);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } finally {
            //关闭连接
            channel.disconnect();
        }
        return resultBuffer.toString();
    }

    /**
     * 执行命令
     *
     * @param command
     * @return
     * @throws Exception
     */
    public String executeShellNoBack(String command) throws Exception {

        byte[] tmp = new byte[1024];
        StringBuffer resultBuffer = new StringBuffer(); // 命令返回的结果

        Channel channel = session.openChannel("exec");
        ChannelExec exec = (ChannelExec) channel;
        // 返回结果流（命令执行错误的信息通过getErrStream获取）
        InputStream stdStream = exec.getInputStream();
        exec.setCommand(command);
        exec.connect();
        try {
            // 开始获得SSH命令的结果
            while (true) {
                while (stdStream.available() > 0) {
                    int i = stdStream.read(tmp, 0, 1024);
                    if (i < 0) break;
                    resultBuffer.append(new String(tmp, 0, i));
                }
                if (exec.isClosed()) {
                    log.info("shell执行返回数据",resultBuffer.toString());
                    break;
                }
                try {
                    Thread.sleep(200);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } finally {
            //关闭连接
            channel.disconnect();
        }
        return resultBuffer.toString();
    }

    /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args)  {
        LinuxShell linux = new LinuxShell();

        linux.login();
        // 简单执行一条指令
        try {
            String res = linux.executeShell("ls");
            if (res != null) {
                System.out.print(res);
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        linux.close();

    }
}
